package com.ymk.base.cmd;


import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.ymk.bo.ListParamType;
import com.ymk.base.BaseVO;
import com.ymk.base.exception.MallException;
import com.ymk.base.utlis.*;
import com.ymk.core.constants.SysConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

public abstract class ACmd implements ICommand, InitializingBean {
    private final static Logger logger = LoggerFactory.getLogger(ACmd.class);

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println(this.getCmdCode());
        this.scheduler.register(this.getCmdCode() + this.getVersion() + this.getDomain(), this);
    }

    public String getVersion() {
        return "1";
    }


    @Override
    public CmdSign execute(HttpServletRequest request, CmdSign sign) throws Exception {
        System.out.println();
        return null;
    }

    @Override
    public CmdSign executeSop(HttpServletRequest request, CmdSign sign) throws Exception {
        return null;
    }

    @Override
    public CmdSign executeMop(HttpServletRequest request, CmdSign sign) throws Exception {
        return null;
    }

    @Override
    public CmdSign executeStore(HttpServletRequest request, CmdSign sign) throws Exception {
        return null;
    }


    @Override
    public CmdSign executeServer(HttpServletRequest request, CmdSign sign) throws Exception {
        return null;
    }

    /**
     * 路由处理
     *
     * @param request
     * @param sign
     * @return
     * @throws Exception
     */
    @Override
    public CmdSign route(HttpServletRequest request, CmdSign sign) throws Exception {
        CmdSign respSign = null;
        if (this.openAuditLogBefore()) {
            try {
                LogUtils.auditLog(logger, sign, this.auditLogBizNo(sign, null));
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

       if (SysConstants.CMD_MOP_SCOPE.equals(sign.getScope())) {
            respSign = this.executeMop(request, sign);
        } else if (SysConstants.CMD_SERVER_SCOPE.equals(sign.getScope())) {
            respSign = this.executeServer(request, sign);
        } else if (SysConstants.CMD_STORE_SCOPE.equals(sign.getScope())) {
            respSign = this.executeStore(request, sign);
        }  else if (SysConstants.CMD_SOP_SCOPE.equals(sign.getScope())) {
           respSign = this.executeSop(request, sign);
       }

        if (respSign == null) {
            respSign = this.execute(request, sign);
        }

        if (respSign == null) {
            throw new MallException("命令方法体未注册");
        }else {
            try {
                if (this.openAuditLogAfter()) {
                    LogUtils.auditLog(logger, sign, this.auditLogBizNo(sign, respSign), this.getAuditLogData(respSign));
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }


        return respSign;
    }

    public boolean deprecated() {
        return false;
    }

    /**
     * 是否允许匿名调用
     *
     * @return
     */
    @Override
    public boolean anon(CmdSign sign) {
        return SysConstants.CMD_SERVER_SCOPE.equals(sign.getScope());
    }

    /**
     * 开启事务
     *
     * @return
     */
    @Override
    public boolean openTx(CmdSign sign) {
        return true;
    }

    /**
     * 验证
     *
     * @return
     */
    @Override
    public CmdSign verify(HttpServletRequest request, CmdSign sign) throws Exception {
        return null;
    }

    /**
     * 鉴权
     *
     * @param request
     * @param sign
     * @return
     * @throws Exception
     */
    public CmdSign authCmd(HttpServletRequest request, CmdSign sign) throws Exception {
        return new CmdSign(sign);
    }


    protected <T> T getData(CmdSign sign, Class<T> clazz) {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
                .registerTypeAdapter(int.class, new IntTypeAdapter())
                .registerTypeAdapter(Integer.class, new IntTypeAdapter())
                .registerTypeAdapter(long.class, new LongTypeAdapter())
                .registerTypeAdapter(Long.class, new LongTypeAdapter())
                .registerTypeAdapter(Date.class, new DateTypeAdapter())
                .registerTypeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
                .create();
        return gson.fromJson(sign.getSource(), clazz);
    }
    protected <T> T getData(String json, Class<T> clazz) {
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
                .registerTypeAdapter(int.class, new IntTypeAdapter())
                .registerTypeAdapter(Integer.class, new IntTypeAdapter())
                .registerTypeAdapter(long.class, new LongTypeAdapter())
                .registerTypeAdapter(Long.class, new LongTypeAdapter())
                .registerTypeAdapter(Date.class, new DateTypeAdapter())
                .registerTypeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
                .create();
        return gson.fromJson(json, clazz);
    }

    protected <T> List<T> getArray(CmdSign sign, Class<T> clazz) {
        Type type = new ListParamType(clazz);
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        return gson.fromJson(sign.getSource(), type);

    }
    protected <T> List<T> getArray(String json, Class<T> clazz) {
        Type type = new ListParamType(clazz);
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        return gson.fromJson(json, type);

    }

    protected String getSource(Object object) {
        if (object == null) {
            return null;
        }
        Gson gson = new GsonBuilder().disableHtmlEscaping().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        return gson.toJson(object);
    }

    protected void setModifiedData(CmdSign sign, BaseVO baseVO) {
        baseVO.setModifiedDate(new Date());
        baseVO.setModifiedBy(sign.getUserId() == null ? 0 : sign.getUserId());
    }

    protected void setCreatedData(CmdSign sign, BaseVO baseVO) {
        baseVO.setCreatedDate(new Date());
        baseVO.setCreatedBy(sign.getUserId() == null ? 0 : sign.getUserId());
        baseVO.setModifiedDate(new Date());
        baseVO.setModifiedBy(sign.getUserId() == null ? 0 : sign.getUserId());
    }

    protected <T extends BaseVO> void setCreatedListData(CmdSign sign, List<T> baseVOList) {
        if (baseVOList != null && baseVOList.size() != 0) {
            for (T baseVO : baseVOList) {
                this.setCreatedData(sign, baseVO);
            }
        }
    }

    protected <T extends BaseVO> void setModifiedListData(CmdSign sign, List<T> baseVOList) {
        if (baseVOList != null && baseVOList.size() != 0) {
            for (T baseVO : baseVOList) {
                this.setModifiedData(sign, baseVO);
            }
        }
    }

    protected boolean isProd() {
        return SysConstants.SERVER_ENV_PROD.equals(SysConstants.SERVER_ENV);
    }

    @Override
    public String lockKey(CmdSign sign) {
        return null;
    }

    @Override
    public boolean openAuditLogBefore() {
        return false;
    }

    @Override
    public boolean openAuditLogAfter() {
        return false;
    }

    @Override
    public String auditLogBizNo(CmdSign reqSign, CmdSign respSign) {
        return "";
    }

    /**
     * 审计日志-获取数据
     *
     * @param respSign
     * @return
     */
    @Override
    public Object getAuditLogData(CmdSign respSign) {
        return respSign.getSource();
    }

    /**
     * 需要执行的下一个指令
     *
     * @return
     */
    @Override
    public String nextCmd() {
        return null;
    }

    @Override
    public String getDomain() {
        return "";
    }

    @Autowired
    protected SchedulerCmd scheduler;
    @Autowired
    protected SchedulerFacade schedulerFacade;


}
